package psn.qiuyiping.autocad.dxffile;

import java.util.function.Consumer;
import java.util.function.Function;

public class DxfProcess {
    @SuppressWarnings("unchecked")
    static Function<DxfData<String>, DxfData<? extends Object>>[] FUNCS = new Function[1080];

    static {
        lexStrings(0, 4);
        lexHex(5);
        lexStrings(6, 9);
        lex3Ds(10, 19);
        lexReals(40, 59);
        lexShorts(60, 79);
        lexIntegers(90, 99);
        lexString(100);
        lexString(102);
        lexHex(105);
        lex3Ds(110, 119);
        lexReals(140, 149);
        lexLongs(160, 169);
        lexShorts(170, 179);
        lex3Ds(210, 219);
        lexShorts(270, 289);
        lexBools(290, 299);
        lexStrings(300, 309);
        lexBinarys(310, 319);
        lexHexs(320, 369);
        lexShorts(370, 389);
        lexHexs(390, 399);
        lexShorts(400, 409);
        lexStrings(410, 419);
        lexIntegers(420, 429);
        lexStrings(430, 439);
        lexIntegers(440, 449);
        lexLongs(450, 459);
        lexReals(460, 469);
        lexStrings(470, 479);
        lexHexs(480, 481);
        lexString(999);
        lexStrings(1000, 1004);
        lexHex(1005);
        lexStrings(1006, 1009);
        lex3Ds(1010, 1019);
        lexReals(1040, 1059);
        lexShorts(1060, 1070);
        lexInteger(1071);
    }

    private static void lex3D(int i) {
        FUNCS[i] = o -> {
            String[] vals = o.getVal().split("\t");
            double[] pt = new double[vals.length];
            for (int iv = 0; iv < vals.length; iv++) {
                pt[iv] = Double.parseDouble(vals[iv]);
            }
            return new DxfData<double[]>(o.getCode(), pt);
        };
    }

    private static void lex3Ds(int i, int j) {
        lexFuncs(i, j, DxfProcess::lex3D);
    }

    private static void lexBinary(int i) {
        FUNCS[i] = (DxfData<String> o) -> {
            String val = o.getVal();
            if ((val.length() & 1) != 0) {
                throw new IllegalArgumentException();
            }
            java.util.List<Byte> bytes = new java.util.ArrayList<>();
            for (int k = 0, j = 0; k < val.length(); k += 2) {
                bytes.add((byte) (Short.parseShort(val.substring(k, k + 2), 16) & 0xFF));
            }
            o.setVal(bytes);
            return o;
        };
    }

    private static void lexBinarys(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexBinary);
    }

    private static void lexBool(int i) {
        FUNCS[i] = o -> new DxfData<Boolean>(o.getCode(),
                0 != Integer.parseInt(o.getVal().trim()));
    }

    private static void lexBools(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexBool);
    }

    private static void lexFuncs(int i, int j, Consumer<Integer> method) {
        for (int is = i; is <= j; is++) {
            method.accept(is);
        }
    }

    private static void lexHex(int i) {
        FUNCS[i] = o -> new DxfData<DxfHandle>(o.getCode(), new DxfHandle(Long.parseLong(o.getVal()
                .trim(), 16)));
    }

    private static void lexHexs(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexHex);
    }

    private static void lexInteger(int i) {
        FUNCS[i] = o -> new DxfData<Integer>(o.getCode(), Integer.parseInt(o
                .getVal().trim()));
    }

    private static void lexIntegers(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexInteger);
    }

    private static void lexLong(int i) {
        FUNCS[i] = (o) -> new DxfData<Long>(o.getCode(), Long.parseLong(o
                .getVal().trim()));
    }

    private static void lexLongs(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexLong);
    }

    private static void lexReal(int i) {
        FUNCS[i] = o -> new DxfData<Double>(o.getCode(), Double.parseDouble(o
                .getVal().trim()));
    }

    private static void lexReals(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexReal);
    }

    private static void lexShort(int i) {
        FUNCS[i] = (o) -> new DxfData<Short>(o.getCode(), Short.parseShort(o
                .getVal().trim()));
    }

    private static void lexShorts(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexShort);
    }

    private static void lexString(int i) {
        FUNCS[i] = o -> o;
    }

    private static void lexStrings(int i, int j) {
        lexFuncs(i, j, DxfProcess::lexString);
    }

    private static void setFunc(int i,
            Function<DxfData<String>, DxfData<? extends Object>> func) {
        if (FUNCS[i] != null) {
            throw new RuntimeException();
        }
        FUNCS[i] = func;
    }

    public Function<DxfData<String>, DxfData<? extends Object>> getFunc(int i) {
        return FUNCS[i];
    }

}
